#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <signal.h>
#include <readline/readline.h>
#include <readline/history.h>

void print_tip()
{
	struct passwd *usrname;
	usrname = getpwuid(getuid());//获取当前用户名
	char buf[256];
	memset(buf,0,sizeof(buf));
	char *path=getcwd(buf,256);
	printf("[my_shell:%s",path);
	//判断用户
	if(strcmp(usrname->pw_name,"root")==0)
		printf("]# ");
	else
		printf("]$ ");
	fflush(stdout);//刷新
}

//获得命令行输入
void get_input(char *buf)
{
	int len = 0;
	char ch;
	ch = getchar();
	while(len < 256 && ch != '\n')
	{
		buf[len++] = ch;
		ch = getchar();
	}
	if(len == 256)
	{
		printf("command is too long\n");
		exit(1);
	}
	buf[len] = '\n';
	buf[++len] = '\0';
}

//解析命令行
void explain_input(char *buf , int *cont , char list[100][256])
{
	int i=0;
	*cont = 0;
	int j;
	while(1)
	{
		if(buf[i] == ' ')
		{
			i++;
			continue;
		}
		if(buf[i] == '\n')
			break;
		else
		{
			j = 0;
			while(buf[i] != ' ' && buf[i] != '\n')
			{
				list[*cont][j] = buf[i];
				j++;
				i++;
			}	
			list[*cont][j] = '\0';
			*cont += 1;
		}
	}
}

void my_cd(const char *p,char list[100][256])
{
	if(strcmp(list[0],"cd") != 0)
		return;
    char path[256];
    char *start;
    char *end;
	int res;
    memset(path,'\0',256); // 初始化，分配内存

    start = strchr(p,' ');//获取路径的标识
    end = strchr(p,'\n');
    if(!start || !end)
    {
        printf("can't support this format \n");
        return ;
    }
    strncpy(path,p+3,end-start-1); // 获得路径
    res = chdir(path); //cd命令实现
    if(res != 0)
        printf("%s 不是一个路径，请重新输入\n",path);
}

void command(int cont,char list[100][256])
{
	if(strcmp(list[0],"cd") == 0)
		return;
	char *arg[256];//存放命令
	char *arg2[256];//存放管道的第二个命令
	pid_t pid=fork();	//创建进程
	int index;	//存放当前重定向符号下标
	int choice=0;	//判断重定向类型	1：>	2：<	11：>>	22：<<	10：|
	int fd;		//文件描述符
	char *file;		//重定向文件
	int statu;
	int i=0;
	for(i=0;i<cont;i++)
		arg[i] = (char*)list[i];
	arg[cont]=NULL;
	
	for(i=0;i<cont;i++)
	{
		if(strcmp(arg[i],">")==0)
		{
			choice+=1;
			file = arg[i+1];
			index=i;
		}
		else if(strcmp(arg[i],"<")==0)
		{
			choice+=2;
			file = arg[i+1];
			index=i;
		}
		else if(strcmp(arg[i],">>")==0)
		{
			choice+=11;
			file = arg[i+1];
			index=i;
		}
		else if(strcmp(arg[i],"<<")==0)
		{
			choice+=22;
			file = arg[i+1];
			index=i;
		}
		else if(strcmp(arg[i],"|")==0)
		{
			choice += 10;
			int c=0;
			for(int j=i+1;j<cont;j++)
			{
				arg2[c]=arg[j];
				c++;
			}
			arg2[c]=NULL;
			index=i;			
		}	
	}

	if(choice!=0)	arg[index]=NULL;//将特殊字符置空
	if(pid<0)	printf("fork error!!!");//进程创建失败
	if(pid==0)//子进程
	{
		//printf("file=%s",file);
		switch(choice)
		{
			case 0:
			{
				execvp(arg[0],arg);
				exit(0);
				break;
			}
			case 10:// |
			{
				int pid2=fork();
				int satu;
				int fd2;//文件描述符
				if(pid2 < 0)	perror("fork error");
				
				if(pid2 == 0)
				{
					if((fd2 = open("/tmp/1.txt",O_WRONLY|O_CREAT|O_TRUNC,0644)) < 0)	perror("open");//1.txt临时文件
					
					dup2(fd2,1);	//1为写文件
					execvp(arg[0],arg);
					exit(0);
				}
				waitpid(pid2,&satu,0);
				close(fd2);
				fd2 = open("/tmp/1.txt",O_RDONLY);
				dup2(fd2,0);	//0为读文件
				execvp(arg2[0],arg2);
				if(remove("/tmp/1.txt") < 0)	perror("remove error");
				exit(0);
				break;
			}
			case 1://	>	
			{
				fd = open(file,O_RDWR|O_CREAT|O_TRUNC,S_IRWXU);//有则写入，没有则创建，清空数据，可读可写可执行				
				dup2(fd,1);
				execvp(arg[0],arg);
				exit(0);
				break;
			}
			case 2://	<
			{
				if((fd = open(file,O_RDONLY,0644)) < 0)	perror("open file error!!!\n");
				dup2(fd,0);
				execvp(arg[0],arg);
				exit(0);
				break;
			}
			case 11://	>>
			{
				fd = open(file,O_RDWR|O_CREAT|O_APPEND,S_IRWXU);
				dup2(fd,1);
				execvp(arg[0],arg);
				exit(0);
				break;
			}
			case 22://	<<
			{
				if((fd = open(file,O_RDONLY)) < 0)	perror("open file error!!!\n");
				dup2(fd,0);
				execvp(arg[0],arg);
				exit(0);
				break;
			}	
			default:printf("input error!!!");
		}
	}
	waitpid(pid,&statu,0);
}


int main()
{
	int cont;
	char list[100][256];
	while(1)
	{
		char *buf = (char*)malloc(sizeof(256));//分配内存
		memset(list,0,sizeof(list));//初始化
		memset(buf,0,sizeof(buf));
		print_tip();
		get_input(buf);	
		explain_input(buf,&cont,list);
		if(strcmp(list[0],"quit") == 0)
			exit(0);
		my_cd(buf,list);
		command(cont,list);
		free(buf);			//释放内存
	}
	return 0;
}
